home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / x+opengl / paperplane.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  12KB  |  368 lines

  1. /* $Revision: 1.1 $ */
  2. /*
  3.  * paperplane can be compiled to use a "single visual" for the entire window
  4.  * hierarchy and render OpenGL into a standard Motif drawing area widget:
  5.  *
  6.  *  cc -o sv_paperplane paperplane.c -DnoGLwidget -lGL -lXm -lXt -lX11 -lm
  7.  *
  8.  * Or paperplane can be compiled to use the default visual for most of
  9.  * the window hierarchy but render OpenGL into a special "OpenGL widget":
  10.  *
  11.  *  cc -o glw_paperplane paperplane.c -lGLw -lGL -lXm -lXt -lX11 -lm 
  12.  */
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <unistd.h>
  16. #include <math.h>
  17. #include <Xm/MainW.h>
  18. #include <Xm/RowColumn.h>
  19. #include <Xm/PushB.h>
  20. #include <Xm/ToggleB.h>
  21. #include <Xm/CascadeB.h>
  22. #include <Xm/Frame.h>
  23. #ifdef noGLwidget
  24. #include <Xm/DrawingA.h>    /* Motif drawing area widget */
  25. #else
  26. /** NOTE: in IRIX 5.2, the OpenGL widget headers are mistakenly in   **/
  27. /** <GL/GLwDrawA.h> and <GL/GlwMDraw.h> respectively.  Below are the **/
  28. /** _official_ standard locations.                                   **/
  29. #ifndef __sgi
  30. #ifdef noMotifGLwidget
  31. #include <X11/GLw/GLwDrawA.h> /* STANDARD: pure Xt OpenGL drawing area widget */
  32. #else
  33. #include <X11/GLw/GLwMDrawA.h> /* STANDARD: Motif OpenGL drawing area widget */
  34. #endif
  35. #else
  36. #ifdef noMotifGLwidget
  37. #include <GL/GLwDrawA.h> /* IRIX 5.2: pure Xt OpenGL drawing area widget */
  38. #else
  39. #include <GL/GLwMDrawA.h> /* IRIX 5.2: Motif OpenGL drawing area widget */
  40. #endif
  41. #endif
  42. #endif
  43. #include <X11/keysym.h>
  44. #include <GL/gl.h>
  45. #include <GL/glu.h>
  46. #include <GL/glx.h>
  47.  
  48. static int dblBuf[] = {
  49.     GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16,
  50.     GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
  51.     None
  52. };
  53. static int *snglBuf = &dblBuf[1];
  54. static String   fallbackResources[] = {
  55. #ifdef IRIX_5_2_or_higher
  56.     "*sgiMode: true",        /* try to enable IRIX 5.2+ look & feel */
  57.     "*useSchemes: all",        /* and SGI schemes */
  58. #endif
  59.     "*title: OpenGL paper plane demo",
  60.     "*glxarea*width: 300", "*glxarea*height: 300", NULL
  61. };
  62. Display     *dpy;
  63. GLboolean    doubleBuffer = GL_TRUE, moving = GL_FALSE, made_current = GL_FALSE;
  64. XtAppContext app;
  65. XtWorkProcId workId = 0;
  66. Widget       toplevel, mainw, menubar, menupane, btn, cascade, frame, glxarea;
  67. GLXContext   cx;
  68. XVisualInfo *vi;
  69. #ifdef noGLwidget
  70. Colormap     cmap;
  71. #endif
  72. Arg          menuPaneArgs[1], args[1];
  73.  
  74. #define MAX_PLANES 15
  75.  
  76. struct {
  77.     float           speed;    /* zero speed means not flying */
  78.     GLfloat         red, green, blue;
  79.     float           theta;
  80.     float           x, y, z, angle;
  81. } planes[MAX_PLANES];
  82.  
  83. #define v3f glVertex3f /* v3f was the short IRIS GL name for glVertex3f */
  84.  
  85. void draw(Widget w)
  86. {
  87.     GLfloat         red, green, blue;
  88.     int             i;
  89.  
  90.     glClear(GL_DEPTH_BUFFER_BIT);
  91.     /* paint black to blue smooth shaded polygon for background */
  92.     glDisable(GL_DEPTH_TEST);
  93.     glShadeModel(GL_SMOOTH);
  94.     glBegin(GL_POLYGON);
  95.         glColor3f(0.0, 0.0, 0.0);
  96.         v3f(-20, 20, -19); v3f(20, 20, -19);
  97.         glColor3f(0.0, 0.0, 1.0);
  98.         v3f(20, -20, -19); v3f(-20, -20, -19);
  99.     glEnd();
  100.     /* paint planes */
  101.     glEnable(GL_DEPTH_TEST);
  102.     glShadeModel(GL_FLAT);
  103.     for (i = 0; i < MAX_PLANES; i++)
  104.     if (planes[i].speed != 0.0) {
  105.         glPushMatrix();
  106.             glTranslatef(planes[i].x, planes[i].y, planes[i].z);
  107.             glRotatef(290.0, 1.0, 0.0, 0.0);
  108.             glRotatef(planes[i].angle, 0.0, 0.0, 1.0);
  109.             glScalef(1.0 / 3.0, 1.0 / 4.0, 1.0 / 4.0);
  110.             glTranslatef(0.0, -4.0, -1.5);
  111.             glBegin(GL_TRIANGLE_STRIP);
  112.                 /* left wing */
  113.                 v3f(-7.0, 0.0, 2.0); v3f(-1.0, 0.0, 3.0);
  114.                 glColor3f(red = planes[i].red, green = planes[i].green,
  115.                           blue = planes[i].blue);
  116.                 v3f(-1.0, 7.0, 3.0);
  117.                 /* left side */
  118.                 glColor3f(0.6 * red, 0.6 * green, 0.6 * blue);
  119.                 v3f(0.0, 0.0, 0.0); v3f(0.0, 8.0, 0.0);
  120.                 /* right side */
  121.                 v3f(1.0, 0.0, 3.0); v3f(1.0, 7.0, 3.0);
  122.                 /* final tip of right wing */
  123.                 glColor3f(red, green, blue);
  124.                 v3f(7.0, 0.0, 2.0);
  125.             glEnd();
  126.         glPopMatrix();
  127.     }
  128.     if (doubleBuffer) glXSwapBuffers(dpy, XtWindow(w));
  129.     if(!glXIsDirect(dpy, cx))
  130.         glFinish(); /* avoid indirect rendering latency from queuing */
  131. #ifdef DEBUG
  132.     { /* for help debugging, report any OpenGL errors that occur per frame */
  133.         GLenum error;
  134.         while((error = glGetError()) != GL_NO_ERROR)
  135.             fprintf(stderr, "GL error: %s\n", gluErrorString(error));
  136.     }
  137. #endif
  138. }
  139.  
  140. void tick_per_plane(int i)
  141. {
  142.     float theta = planes[i].theta += planes[i].speed;
  143.     planes[i].z = -9 + 4 * cos(theta);
  144.     planes[i].x = 4 * sin(2 * theta);
  145.     planes[i].y = sin(theta / 3.4) * 3;
  146.     planes[i].angle = ((atan(2.0) + M_PI_2) * sin(theta) - M_PI_2) * 180 / M_PI;
  147.     if (planes[i].speed < 0.0) planes[i].angle += 180;
  148. }
  149.  
  150. void add_plane(void)
  151. {
  152.     int i;
  153.  
  154.     for (i = 0; i < MAX_PLANES; i++)
  155.     if (planes[i].speed == 0) {
  156.  
  157. #define SET_COLOR(r,g,b) \
  158.     planes[i].red=r; planes[i].green=g; planes[i].blue=b; break;
  159.  
  160.             switch (random() % 6) {
  161.             case 0: SET_COLOR(1.0, 0.0, 0.0); /* red */
  162.             case 1: SET_COLOR(1.0, 1.0, 1.0); /* white */
  163.             case 2: SET_COLOR(0.0, 1.0, 0.0); /* green */
  164.             case 3: SET_COLOR(1.0, 0.0, 1.0); /* magenta */
  165.             case 4: SET_COLOR(1.0, 1.0, 0.0); /* yellow */
  166.             case 5: SET_COLOR(0.0, 1.0, 1.0); /* cyan */
  167.             }
  168.             planes[i].speed = (random() % 20) * 0.001 + 0.02;
  169.             if (random() & 0x1) planes[i].speed *= -1;
  170.         planes[i].theta = ((float) (random() % 257)) * 0.1111;
  171.         tick_per_plane(i);
  172.         if (!moving) draw(glxarea);
  173.         return;
  174.     }
  175.     XBell(dpy, 100); /* can't add any more planes */
  176. }
  177.  
  178. void remove_plane(void)
  179. {
  180.     int             i;
  181.  
  182.     for (i = MAX_PLANES - 1; i >= 0; i--)
  183.     if (planes[i].speed != 0) {
  184.         planes[i].speed = 0;
  185.         if (!moving) draw(glxarea);
  186.         return;
  187.     }
  188.     XBell(dpy, 100); /* no more planes to remove */
  189. }
  190.  
  191. void resize(Widget w, XtPointer data, XtPointer callData)
  192. {
  193.     Dimension       width, height;
  194.  
  195.     if(made_current) {
  196.     XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
  197.     glViewport(0, 0, (GLint) width, (GLint) height);
  198.     }
  199. }
  200.  
  201. void tick(void)
  202. {
  203.     int i;
  204.  
  205.     for (i = 0; i < MAX_PLANES; i++)
  206.     if (planes[i].speed != 0.0) tick_per_plane(i);
  207. }
  208.  
  209. Boolean animate(XtPointer data)
  210. {
  211.     tick();
  212.     draw(glxarea);
  213.     return False;        /* leave work proc active */
  214. }
  215.  
  216. void toggle(void)
  217. {
  218.     moving = !moving; /* toggle */
  219.     if (moving)
  220.     workId = XtAppAddWorkProc(app, animate, NULL);
  221.     else
  222.     XtRemoveWorkProc(workId);
  223. }
  224.  
  225. void quit(Widget w, XtPointer data, XtPointer callData)
  226. {
  227.     exit(0);
  228. }
  229.  
  230. void input(Widget w, XtPointer data, XtPointer callData)
  231. {
  232.     XmDrawingAreaCallbackStruct *cd = (XmDrawingAreaCallbackStruct *) callData;
  233.     char            buf[1];
  234.     KeySym          keysym;
  235.     int             rc;
  236.  
  237.     if(cd->event->type == KeyPress)
  238.     if(XLookupString((XKeyEvent *) cd->event, buf, 1, &keysym, NULL) == 1)
  239.         switch (keysym) {
  240.         case XK_space:
  241.             if (!moving) { /* advance one frame if not in motion */
  242.                 tick();
  243.             draw(w);
  244.             }
  245.             break;
  246.         case XK_Escape:
  247.             exit(0);
  248.         }
  249. }
  250.  
  251. void map_state_changed(Widget w, XtPointer data, XEvent * event, Boolean * cont)
  252. {
  253.     switch (event->type) {
  254.     case MapNotify:
  255.     if (moving && workId != 0) workId = XtAppAddWorkProc(app, animate, NULL);
  256.     break;
  257.     case UnmapNotify:
  258.     if (moving) XtRemoveWorkProc(workId);
  259.     break;
  260.     }
  261. }
  262.  
  263. main(int argc, char *argv[])
  264. {
  265.     toplevel = XtAppInitialize(&app, "Paperplane", NULL, 0, &argc, argv,
  266.                    fallbackResources, NULL, 0);
  267.     dpy = XtDisplay(toplevel);
  268.     /* find an OpenGL-capable RGB visual with depth buffer */
  269.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf);
  270.     if (vi == NULL) {
  271.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf);
  272.     if (vi == NULL)
  273.         XtAppError(app, "no RGB visual with depth buffer");
  274.     doubleBuffer = GL_FALSE;
  275.     }
  276.     /* create an OpenGL rendering context */
  277.     cx = glXCreateContext(dpy, vi, /* no display list sharing */ None,
  278.         /* favor direct */ GL_TRUE);
  279.     if (cx == NULL)
  280.     XtAppError(app, "could not create rendering context");
  281.     /* create an X colormap since probably not using default visual */
  282. #ifdef noGLwidget
  283.     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
  284.         vi->visual, AllocNone);
  285.     /*
  286.      * Establish the visual, depth, and colormap of the toplevel
  287.      * widget _before_ the widget is realized.
  288.      */
  289.     XtVaSetValues(toplevel, XtNvisual, vi->visual, XtNdepth, vi->depth,
  290.           XtNcolormap, cmap, NULL);
  291. #endif
  292.     XtAddEventHandler(toplevel, StructureNotifyMask, False,
  293.                       map_state_changed, NULL);
  294.     mainw = XmCreateMainWindow(toplevel, "mainw", NULL, 0);
  295.     XtManageChild(mainw);
  296.     /* create menu bar */
  297.     menubar = XmCreateMenuBar(mainw, "menubar", NULL, 0);
  298.     XtManageChild(menubar);
  299. #ifdef noGLwidget
  300.     /* Hack around Xt's unfortunate default visual inheritance. */
  301.     XtSetArg(menuPaneArgs[0], XmNvisual, vi->visual);
  302.     menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
  303. #else
  304.     menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
  305. #endif
  306.     btn = XmCreatePushButton(menupane, "Quit", NULL, 0);
  307.     XtAddCallback(btn, XmNactivateCallback, quit, NULL);
  308.     XtManageChild(btn);
  309.     XtSetArg(args[0], XmNsubMenuId, menupane);
  310.     cascade = XmCreateCascadeButton(menubar, "File", args, 1);
  311.     XtManageChild(cascade);
  312. #ifdef noGLwidget
  313.     menupane = XmCreatePulldownMenu(menubar, "menupane", menuPaneArgs, 1);
  314. #else
  315.     menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0);
  316. #endif
  317.     btn = XmCreateToggleButton(menupane, "Motion", NULL, 0);
  318.     XtAddCallback(btn, XmNvalueChangedCallback, (XtCallbackProc)toggle, NULL);
  319.     XtManageChild(btn);
  320.     btn = XmCreatePushButton(menupane, "Add plane", NULL, 0);
  321.     XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)add_plane, NULL);
  322.     XtManageChild(btn);
  323.     btn = XmCreatePushButton(menupane, "Remove plane", NULL, 0);
  324.     XtAddCallback(btn, XmNactivateCallback, (XtCallbackProc)remove_plane, NULL);
  325.     XtManageChild(btn);
  326.     XtSetArg(args[0], XmNsubMenuId, menupane);
  327.     cascade = XmCreateCascadeButton(menubar, "Planes", args, 1);
  328.     XtManageChild(cascade);
  329.     /* create framed drawing area for OpenGL rendering */
  330.     frame = XmCreateFrame(mainw, "frame", NULL, 0);
  331.     XtManageChild(frame);
  332. #ifdef noGLwidget
  333.     glxarea = XtVaCreateManagedWidget("glxarea", xmDrawingAreaWidgetClass,
  334.                                       frame, NULL);
  335. #else
  336. #ifdef noMotifGLwidget
  337.     /* notice glwDrawingAreaWidgetClass lacks an 'M' */
  338.     glxarea = XtVaCreateManagedWidget("glxarea", glwDrawingAreaWidgetClass,
  339. #else
  340.     glxarea = XtVaCreateManagedWidget("glxarea", glwMDrawingAreaWidgetClass,
  341. #endif
  342.                       frame, GLwNvisualInfo, vi, NULL);
  343. #endif
  344.     XtAddCallback(glxarea, XmNexposeCallback, (XtCallbackProc)draw, NULL);
  345.     XtAddCallback(glxarea, XmNresizeCallback, resize, NULL);
  346.     XtAddCallback(glxarea, XmNinputCallback, input, NULL);
  347.     /* set up application's window layout */
  348.     XmMainWindowSetAreas(mainw, menubar, NULL, NULL, NULL, frame);
  349.     XtRealizeWidget(toplevel);
  350.     /*
  351.      * Once widget is realized (ie, associated with a created X window), we
  352.      * can bind the OpenGL rendering context to the window.
  353.      */
  354.     glXMakeCurrent(dpy, XtWindow(glxarea), cx);
  355.     made_current = GL_TRUE;
  356.     /* setup OpenGL state */
  357.     glClearDepth(1.0);
  358.     glClearColor(0.0, 0.0, 0.0, 0.0);
  359.     glMatrixMode(GL_PROJECTION);
  360.     glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 20);
  361.     glMatrixMode(GL_MODELVIEW);
  362.     /* add three initial random planes */
  363.     srandom(getpid());
  364.     add_plane(); add_plane(); add_plane();
  365.     /* start event processing */
  366.     XtAppMainLoop(app);
  367. }
  368.